#!/usr/bin/python3
# -*- coding: utf8 -*-
# Date   : 2021/06/27
# Author : Kwan
# Email  : allenxian@live.com
# Blog   : https://my.oschina.net/u/4173440

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_app
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin, AnonymousUserMixin
from project.flasky import db
from project.define import db_logger, PermissionsModule
from .role import Role


class User(UserMixin, db.Model):
    """
    登陆用户
    """
    __tablename__ = 'app_user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True, nullable=False)
    # 登录名
    LoginName = db.Column(db.String(64), nullable=False, unique=True)
    # 用户名
    UserName = db.Column(db.String(64), nullable=False)
    # 联系电话
    Phone = db.Column(db.String(16))
    # 密码
    PasswordHash = db.Column(db.String(128))
    # 启用状态
    Active = db.Column(db.Boolean, default=True)
    # 收费处ID
    CashierName = db.Column(db.String(128))
    # 收费班次: 1.白班 2.夜班 3.全日
    CashClass = db.Column(db.Integer)
    # 权限ID
    RoleID = db.Column(db.Integer, db.ForeignKey('app_role.id'))
    Deleted = db.Column(db.Boolean, default=False)

    def __init__(self, **kwargs):
        super(User, self).__init__(**kwargs)
        self.LoginName = kwargs.get('LoginName')
        self.UserName = kwargs.get('UserName')
        self.Phone = kwargs.get('Phone')
        # 收费处
        self.CashierName = kwargs.get('CashierName')
        # 班次
        self.CashClass = kwargs.get('CashClass')
        self.RoleID = kwargs.get('RoleID')

    def to_dict(self):
        """
        返回键值对
        """
        return dict([(c.name, getattr(self, c.name)) for c in self.__table__.columns if c.name != 'PasswordHash'])

    def role_name_desc(self, *args):
        """
        角色名
        """
        for i in args:
            if self.RoleID == i['id']:
                return i['Description']

    def role_description(self, *args):
        """
        权限名称
        """
        for i in args:
            if self.RoleID == i.id:
                return i.Description
        
    def update(self, **kwargs):
        """
        更新用户
        """
        row = self.to_dict()
        for k, v in kwargs.items():
            if k == "Password":
                if len(v) >= 6: self.set_password(v)
            elif k in row:
                if v != row[k]: self.__setattr__(k, v)    

    def can(self, perm):
        """
        权限检查
        """
        role = Role.query.filter_by(id=self.RoleID).first()
        if role:
            return role.has_permission(perm)

    def is_admin(self):
        """
        是否为管理员
        """
        return self.can(PermissionsModule.admin)

    def is_guest(self):
        return False

    def set_password(self, password):
        """
        设置加密
        """
        self.PasswordHash = generate_password_hash(password)

    def verify_password(self, password):
        """
        解密认证
        """
        return check_password_hash(self.PasswordHash, password)

    def generate_auth_token(self, expiration=3600):
        """
        生成token
        """
        s = Serializer(current_app.config['SECRET_KEY'], expires_in=expiration)
        return s.dumps({'id': self.id}).decode('utf8')

    @staticmethod
    def verify_auth_token(token):
        """
        token认证
        """
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
            return User.query.get(data['id'])
        except Exception as e:
            db_logger.error(f"认证错误：{e}")

    @property
    def password(self):
        """
        屏蔽password关键字
        """
        raise AttributeError ('password is not a readable attribute')

    @staticmethod
    def selected_data(**kwargs):
        """
        选中数据
        """
        user_id = kwargs.get('id')
        if user_id:
            return User.query.filter_by(id=user_id).first()

    @staticmethod
    def columns_name():
        """
        数据表标题
        """
        ColumnName = {
            'id': '用戶ID', 'LoginName': '登錄名稱', 'UserName': '用戶名稱', 'Password': '登錄密碼', 'RoleID': '用戶權限','Phone': '聯係電話',
            'CashierName': '收費處'
            }
        return ColumnName

    @staticmethod
    def generate_filters(**kwargs):
        """
        生成筛选器
        """
        filters = set()
        for k, v in kwargs.items():
            if v:
                if k == "LoginName":
                    filters.add(User.LoginName==v)
                elif k == "UserName":
                    filters.add(User.UserName.like(f"%{v}%"))
                elif k == "RoleID":
                    if isinstance(v, int):
                        filters.add(User.RoleID==v)
                    elif len(v) > 1:
                        filters.add(User.RoleID.in_(v))
                elif k == "CashierName":
                    filters.add(User.CashierName.in_(v))
        return filters

    @staticmethod
    def insert_data(**kwargs):
        """
        新增
        """
        try:
            pwd = kwargs.pop("Password")
            r = User(**kwargs)
            r.set_password(pwd)
            db.session.add(r)
            db.session.commit()
            db_logger.debug(f"app_user => 新增用户成功：{kwargs}")
            return r.to_dict()
        except Exception as e:
            db.session.rollback()
            db_logger.error(f"app_user => 新增用户失败：{kwargs} 原因：{e}")

    @staticmethod
    def insert_default_cashier_user(*args):
        """
        插入默认收费员
        """
        try:
            update = False
            r = Role.query.filter_by(Name="user").first()
            for i, c in enumerate(args):
                CashierName = c.get('CashierName')
                demo_user = {"LoginName":f"user{i+1}","UserName":f"{CashierName}收費員","CashierName":CashierName,"RoleID":r.id}
                u = User.query.filter_by(LoginName=demo_user.get('LoginName')).first()
                if not u:
                    u = User(**demo_user)
                    u.set_password("123456")
                    db.session.add(u)
                    update = True
            if update:
                db.session.commit()
                db_logger.debug(f"添加默认收费员成功")
        except Exception as e:
            db.session.rollback()
            db_logger.error(f"app_user => 新增收费员失败！ 原因：{e}")

    @staticmethod
    def delete_data(**kwargs):
        """
        删除
        """
        try:
            r = User.selected_data(**kwargs)
            if r:
                db.session.delete(r)
                db.session.commit()
                db_logger.debug(f"app_user => 删除用户成功：{kwargs}")
                return r.to_dict()
        except Exception as e:
            db.session.rollback()
            db_logger.error(f"app_user => 删除用户失败：{kwargs} 原因：{e}")
        
    @staticmethod
    def table_init():
        """
        插入默认用户数据
        """
        update = False
        roles = Role.query.all()
        users = [{'LoginName': i.Name, 'UserName': i.Description, 'RoleID': i.id} for i in roles]
        for i in users:
            LoginName = i.get('LoginName')
            row = User.query.filter_by(LoginName=LoginName).first()
            if not row:
                row = User(**i)
                row.set_password("123456")
                db.session.add(row)
                update = True
        if update:
            db_logger.debug(f"app_user：初始化成功！")
            db.session.commit()


class AnonymousUser(AnonymousUserMixin):
    """
    匿名用户
    """
    def can(self, permissons):
        return False

    def is_admin(self):
        return False

    def is_guest(self):
        return True

